﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Reflection;

namespace AppiSynchro.Library.Helpers
{
    public class ApplicationInfoHelper
    {
        public static IApplicationInfo LoadXml(String xmlFile)
        {
            Dictionary<String, String> args = new Dictionary<string, string>();
            if (!File.Exists(xmlFile))
                throw new FileLoadException("File not found");

            XmlDocument doc = new XmlDocument();

            doc.Load(xmlFile);

            XmlNodeList nodeList = doc.SelectNodes("/AppiSynchroSetup/Key");
            
            foreach (XmlNode node in nodeList)
                args.Add(node.Attributes["name"].InnerXml, node.InnerXml);

            IInstallationPipeLine pipeLine = LoadInstallationPipelinePlugin(args, doc);

            return LoadApplicationInfoPlugin(args, doc, pipeLine);
        }

        private static IInstallationPipeLine LoadInstallationPipelinePlugin(Dictionary<String, String> args, XmlDocument doc)
        {
            String assemblyFile = doc.SelectSingleNode("/AppiSynchroSetup/InstallationPipeLine/Configuration/Assembly").InnerXml;
            String className = doc.SelectSingleNode("/AppiSynchroSetup/InstallationPipeLine/Configuration/ClassName").InnerXml;

            String setupFile = doc.SelectSingleNode("/AppiSynchroSetup/InstallationPipeLine/Setup/Filename").InnerXml;

            if (!File.Exists(assemblyFile))
                throw new FileLoadException("Assembly file not found");

            Assembly plugin = Assembly.LoadFrom(assemblyFile);

            foreach (Type t in plugin.GetTypes())
            {
                if (t.Name != className)
                    continue;
                Type typeInter = t.GetInterfaces()[0];
                if ((typeInter == typeof(IInstallationPipeLine)) && (t.IsAbstract == false))
                {
                    IInstallationPipeLine b = t.InvokeMember(null,
                                       BindingFlags.CreateInstance,
                                       null, null, null) as IInstallationPipeLine;
                    b.Init(setupFile, args);
                    return b;
                }
            }
            return null;
        }

        private static IApplicationInfo LoadApplicationInfoPlugin(Dictionary<String, String> args, XmlDocument doc, IInstallationPipeLine pipeLine)
        {
            String programName = doc.SelectSingleNode("/AppiSynchroSetup/Setup/Name").InnerXml;
            String programLatestVersion = doc.SelectSingleNode("/AppiSynchroSetup/Setup/LatestVersion").InnerXml;

            String assemblyFile = doc.SelectSingleNode("/AppiSynchroSetup/ApplicationInfo/Configuration/Assembly").InnerXml;
            String className = doc.SelectSingleNode("/AppiSynchroSetup/ApplicationInfo/Configuration/ClassName").InnerXml;

            if (!File.Exists(assemblyFile))
                throw new FileLoadException("Assembly file not found");

            Assembly plugin = Assembly.LoadFrom(assemblyFile);

            foreach (Type t in plugin.GetTypes())
            {
                if (t.Name != className)
                    continue;
                Type typeInter = t.GetInterfaces()[0];
                if ((typeInter == typeof(IApplicationInfo)) && (t.IsAbstract == false))
                {
                    IApplicationInfo b = t.InvokeMember(null,
                                       BindingFlags.CreateInstance,
                                       null, null, null) as IApplicationInfo;

                    b.Init(programName, programLatestVersion, args, pipeLine);

                    return b;
                }
            }
            return null;
        }
    }
}
